import axios from 'axios'

interface FieldConfig {
  label: string
  rules: string[]
  msg?: string
}

export interface ValidateRules {
  [field: string]: FieldConfig
}

/**
 * 默认正则规则
 */
const rules: { [key: string]: any[] } = {
  num: [/^-?\d*\.?\d+$/, '必须是数字'],
  int: [/^-?\d+$/, '必须是整数'],
  intzs: [/^\d+$/, '必须是正整数'],
  intfs: [/^-\\d+$/, '必须是负整数'],
  abc: [/^[a-z]+$/i, '必须是字母'],
  cn: [/^[\u4e00-\u9fa5]+$/, '必须是中文'],
  money: [/^(?!0\.00)(?:0|[1-9]\d*)(?:\.\d{1,2})?$/, '必须是有效的金额'],
  date: [/^\d{4}-\d{2}-\d{2}$/, '必须是有效的日期，格式:yyyy-mm-dd'],
  time: [/^([01]\d|2[0-3])(:[0-5]\d){1,2}$/, '必须是有效的时间，00:00到23:59之间'],

  email: [/^[\w\+\-]+(\.[\w\+\-]+)*@[a-z\d\-]+(\.[a-z\d\-]+)*\.([a-z]{2,4})$/i, '必须是有效的邮箱'],
  url: [/^(https?|s?ftp):\/\/\S+$/i, '必须是有效的网址'],
  qq: [/^[1-9]\d{4,}$/, '必须是有效的QQ号'],
  tel: [/^(?:(?:0\d{2,3}[\- ]?[1-9]\d{6,7})|(?:[48]00[\- ]?[1-9]\d{6}))$/, '必须是有效的电话号码'],
  mobile: [/^1[3-9]\d{9}$/, '必须是有效的手机号'],
  zipcode: [/^\d{6}$/, '请检查邮政编码格式'],
  bankcard: [/^\d{16,19}$/, '必须是有效的银行卡号'],
  idcard: [
    /^\d{6}(19|2\d)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)?$/,
    '必须是正确的身份证号码'
  ],
  ip: [
    /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
    '必须是有效的IPv4地址'
  ],
  port: [
    /^(0|[1-9]\d{0,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/,
    '必须是有效的端口号'
  ],
  username: [/^\w{3,12}$/, '必须是3-12位数字、字母、下划线'],
  password: [/^[\S]{6,16}$/, '必须是6-16位字符，不能包含空格'],
  eovacode: [/^\w{3,50}$/, '必须是3-50位数字、字母、下划线组成']
}

/**
 * 用户自定义校验规则
 */
const diyRules: { [key: string]: any } = {
  'diy[test]': (val: any) => {
    if (val == null) {
      return '自定义为空校验!'
    }
    return null
  }
}

export class ValidateTool {
  /**
   * 注册自定义校验规则
   * @param key
   * @param func
   */
  addRules(key: string, func: any) {
    diyRules[`diy[${key}]`] = func
  }

  /**
   * 开始校验(同步等待生效)
   * @param formRules 表单校验规则
   * @param formData 表单数据
   * @returns
   */
  start(formRules: ValidateRules, formData: any): boolean {
    // 校验规则配置
    Object.entries(formRules).forEach(([field, v]) => {
      let val = formData[field]
      v.msg = ''
      // 遍历校验规则
      for (let rule of v.rules) {
        // 去空格
        rule = rule.trim()
        console.log(`EovaValidlate: ${field} >> ${rule} | ${val}`)

        // 必填
        if (rule == 'required') {
          if (val == null || val == undefined || val == '') {
            v.msg = `${v.label}不能为空`
            break
          }
        }

        // 默认正则
        else if (rule in rules) {
          if (!rules[rule][0].test(String(val))) {
            v.msg = `${v.label}${rules[rule][1]}`
            break
          }
        }

        // len[n] len[1~5]
        else if (rule.startsWith('len[') && rule.endsWith(']')) {
          let n = rule.replace('len[', '').replace(']', '')
          if (n.includes('~')) {
            const ns = n.split('~')
            if (!new RegExp(`^.{${ns[0]},${ns[1]}}$`).test(String(val))) {
              v.msg = `${v.label}必须是 ${ns[0]}~${ns[1]} 个字符`
              break
            }
          } else {
            if (!new RegExp(`^.{${n}}$`).test(String(val))) {
              v.msg = `${v.label}必须是 ${n} 个字符`
              break
            }
          }
        }

        // range[100~200]
        else if (rule.startsWith('range[') && rule.endsWith(']')) {
          let n = rule.replace('range[', '').replace(']', '')
          if (!n.includes('~')) {
            return
          }
          const ns = n.split('~')
          if (!(ns[0] <= val && val <= ns[1])) {
            v.msg = `${v.label}必须是 ${ns[0]}~${ns[1]} 的数`
            break
          }
        }

        // match[password] match[aa,!=]
        else if (rule.startsWith('match[') && rule.endsWith(']')) {
          let n = rule.replace('match[', '').replace(']', '')

          const ns = n.split(',')

          const matchField = ns[0] // 字段
          const matchFieldVal = formData[matchField]
          const matchFieldTxt = formRules[matchField].label
          const op = ns[1] // 逻辑符

          if (op == null || op == '=') {
            if (val != matchFieldVal) {
              v.msg = `${v.label}必须与 ${matchFieldTxt} 相同`
              break
            }
          }
          if (op == '!=') {
            if (val == matchFieldVal) {
              v.msg = `${v.label}不能与 ${matchFieldTxt} 相同`
              break
            }
          }
        }

        // 自定义校验 diy[xxx]
        else if (rule.startsWith('diy[')) {
          // 执行自定义规则的函数
          const info = diyRules[rule](val)
          if (info != null && info != '') {
            v.msg = `${v.label} ${info}`
          }
        } else {
          // 远程异步校验
          if (rule.startsWith('api[')) {
            /*
             * 远程接口校验
             * api[/user/validate?type=id]
             * @return 文本 => 校验失败
             * @return ''   => 校验成功
             */
            let url = rule.replace('api[', '').replace(']', '')
            axios
              .post(`${url}?val=${val}`)
              .then((res) => {
                let ret = res.data
                if (ret != null || ret != '') {
                  console.log(ret)
                  v.msg = `${v.label} ${ret}`
                }
              })
              .catch((e) => {
                console.error(e)
                alert('API校验异常:' + url)
              })
            // 异步校验, 执行后等待异步结果.
            break
          } else {
            console.log(`未知校验规则: ${field} = ${rule}`)
          }
        }
      }

      // console.log(msg)
    })

    // 无错误, 校验通过
    return Object.values(formRules).every((v) => v.msg === '')
  }

  /**
   * 显示校验提示消息
   * @param formRules
   */
  showMsg(formRules: ValidateRules) {
    let o = formRules
    // Object.keys(o).some((key) => {
    //   let s = o[key].msg
    //   if (s) {
    //     x.layer.msg(s)
    //     return true
    //   }
    // })
    // 一次性显示多字段的提示
    let txt = ''
    Object.keys(o).forEach((key) => {
      if (o[key].msg) txt += o[key].msg + '<br>'
    })
    return txt;
  }
}
